/**************************************************************************** 
* 
* Copyright (c) 2023  C*Core -   All Rights Reserved  
* 
* THIS SOFTWARE IS DISTRIBUTED "AS IS," AND ALL WARRANTIES ARE DISCLAIMED, 
* INCLUDING MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* 
* PROJECT     : CCFC2011BC           
* DESCRIPTION : CCFC2011BC can low level drivers code 
* HISTORY     : Initial version.
* @file     can_lld.h
* @version  1.1
* @date     2023 - 02 - 20
* @brief    Initial version.
*
*****************************************************************************/
#ifndef CANFD_LLD_H_
#define CANFD_LLD_H_

#include "CCFC2011BC.h"
#include "common.h"
#include "lldconf.h"
#include "intc_lld.h"
#include "sys.h"
#include "console.h"

#ifndef NULL
#define NULL 0
#endif

#ifndef ENABLE
#define ENABLE 1
#endif
#ifndef DISABLE
#define DISABLE 0
#endif

#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif

#define CANFD_MAX_FILTER_NUM        16U

#define CANFD_MOD_ID_0_INT_NUM      234U
#define CANFD_MOD_ID_1_INT_NUM      235U
#define CANFD_MOD_ID_2_INT_NUM      236U
#define CANFD_MOD_ID_3_INT_NUM      237U
#define CANFD_MOD_ID_4_INT_NUM      238U
#define CANFD_MOD_ID_5_INT_NUM      239U

/* CANFD interface error code */
#define CANFD_OK                    0U
#define CANFD_ERROR_INVALID_PARA    1U
#define CANFD_ERROR_INVALID_STATE   2U
#define CANFD_ERROR_TRANS_BUF_BUSY  3U
#define CANFD_ERROR_NO_MSG_RECEIVED 4U
#define CANFD_ERROR_ABORT_MSG_TRANS 5U

/* CANFD module ID */
typedef enum {
    CANFD_MOD_ID_0,
    CANFD_MOD_ID_1,
    CANFD_MOD_ID_2,
    CANFD_MOD_ID_3,
    CANFD_MOD_ID_4,
    CANFD_MOD_ID_5,
    CANFD_MOD_BUTT
} CANFDModId;

/* CANFD bit rate */
typedef enum  {
    CANFD_MBPS_8,
    CANFD_MBPS_4,
    CANFD_MBPS_2,
    CANFD_MBPS_1,
    CANFD_KBPS_500,
    CANFD_KBPS_400,
    CANFD_KBPS_200,
    CANFD_KBPS_125,
    CANFD_KBPS_100,
    CANFD_BIT_RATE_BUTT
} CANFDBitRate;

/* CANFD data length */
typedef enum
{
    /* within 8 bytes, the DLC value is the same as the data length */
    CANFD_DLC_12_BYTES = 9UL,
    CANFD_DLC_16_BYTES,
    CANFD_DLC_20_BYTES,
    CANFD_DLC_24_BYTES,
    CANFD_DLC_32_BYTES,
    CANFD_DLC_48_BYTES,
    CANFD_DLC_64_BYTES,
    CANFD_DLC_TYPE_BUTT
} CANFD_DlcType; /* PRQA S 1535 # useful */

typedef struct {
    uint8_t seg1; /* include SYNC_SEG, PROP_SEG and PHASE_SEG1 */
    uint8_t seg2;
    uint8_t sjw;
    uint8_t ssp;
    uint8_t prescaler;
} CANFDTimeSeg;

typedef volatile struct FLEXCANFD_tag CANFDReg;

/* CANFD RX message */
typedef struct {
    uint32_t id;
    union {
        uint8_t   byte[64];
        uint32_t  word[16];
    } data;
    uint8_t is_extern;
    uint8_t is_remote;
    uint8_t is_canfd;
    uint8_t is_bit_rate_changed;
    uint16_t timestamp;
    uint8_t data_len;
} CANFDRxMsg;

/* CANFD TX BUF */
typedef enum {
    CANFD_TRANS_BUF_TYPE_PRIMARY,
    CANFD_TRANS_BUF_TYPE_SECONDARY,
    CANFD_TRANS_BUF_TYPE_BUTT
} CANFDTransBufType;

/* CANFD TX message */
typedef struct {
    uint32_t id;
    union {
        uint8_t   byte[64];
        uint32_t  word[16];
    } data;
    uint8_t data_len;
    uint8_t is_extern;
    uint8_t is_remote;
    uint8_t is_fd_format_flag;
    uint8_t is_bit_rate_switch;
    uint8_t is_time_stamp_en;
    CANFDTransBufType trans_buf;
} CANFDTxMsg;

/* CANFD mode */
typedef enum {
    CANFD_CUR_MODE_INIT,
    CANFD_CUR_MODE_NORMAL,
    CANFD_CUR_MODE_SLEEP,
    CANFD_CUR_MODE_FREEZE,
    CANFD_CUR_MODE_LISTEN_ONLY,
    CANFD_CUR_MODE_INNER_LOOP_BACK,
    CANFD_CUR_MODE_OUTER_LOOP_BACK,
    CANFD_CUR_MODE_BUTT
} CANFDCurMode;

/* CANFD error statistics */
typedef struct {
    uint32_t rx_error_cnt;
    uint32_t tx_error_cnt;
} CANFDCurError;

/* CANFD state */
typedef struct {
    CANFDCurMode cur_mode;
    CANFDCurError cur_error;
} CANFDState;

/* CANFD driver descriptor */
typedef struct {
    CANFDModId id;
    CANFDState state;
} CANFDDriver;

/* CANFD Protocol physical layer parameters */
typedef struct {
    uint8_t use_bus_clk_src;
    CANFDBitRate preamble_bit_rate;
    CANFDBitRate data_bit_rate;
} CANFDPhyPara;

/* CANFD function switch */
typedef struct {
    uint8_t tdc_en;
    uint8_t inner_loop_back_en;
    uint8_t outer_loop_back_en;
    uint8_t listen_only_en;
} CANFDFuncSwitch;

/* CAN filter parameter */
typedef struct {
    uint8_t is_valid;
    uint8_t resv;
    uint32_t id;
    uint32_t mask; /* For bits is set to 1, the receiving ID must be the same as the filtering ID */
} CANFDFilter;

/* CANFD Interrupt callback */
typedef struct {
    void (* tx_transferred)(CANFDDriver *drv, CANFDTransBufType buf_idx);
    void (* rx_received)(CANFDDriver *drv, CANFDRxMsg * rx_msg);
    void (* error)(CANFDDriver *drv);
} CANFDIntrCallback;

/* CANFD configuration parameter */
typedef struct {
    CANFDModId canfd_id;
    CANFDPhyPara phy_para;
    CANFDFuncSwitch func_switch;
    CANFDFilter filter[CANFD_MAX_FILTER_NUM];
    CANFDIntrCallback call_back;
} CANFDConfig;

typedef union {
    uint32_t id;
    struct {
        uint32_t is_valid : 1; /* PRQA S 0632 # useful */
        uint32_t msg_cnt : 31; /* PRQA S 0632 # useful */
    } attr;
} CanfdTransBufMsgId;

typedef struct {
    uint32_t cur_msg;
} CanfdTransBufState;

static void Canfd_LLD_Intr_Callback(CANFDModId canfd_id); /* PRQA S 0554, declaration */

#define CANFD_LLD_INTR_HANDLER_NAME(_canfd_id) Canfd_LLD_Intr_Handler_##_canfd_id /* PRQA S 0342 # use ## */
#define CANFD_LLD_INTR_HANDLER_FUNC(_canfd_id) static inline void Canfd_LLD_Intr_Handler_##_canfd_id() /* PRQA S 0342, 1029 # use ## */ \
{ \
    Canfd_LLD_Intr_Callback(_canfd_id); \
}

CANFD_LLD_INTR_HANDLER_FUNC(CANFD_MOD_ID_0); /* PRQA S 0605, 3007 # macro function */
CANFD_LLD_INTR_HANDLER_FUNC(CANFD_MOD_ID_1); /* PRQA S 0605, 3007 # macro function */
CANFD_LLD_INTR_HANDLER_FUNC(CANFD_MOD_ID_2); /* PRQA S 0605, 3007 # macro function */
CANFD_LLD_INTR_HANDLER_FUNC(CANFD_MOD_ID_3); /* PRQA S 0605, 3007 # macro function */
CANFD_LLD_INTR_HANDLER_FUNC(CANFD_MOD_ID_4); /* PRQA S 0605, 3007 # macro function */
CANFD_LLD_INTR_HANDLER_FUNC(CANFD_MOD_ID_5); /* PRQA S 0605, 3007 # macro function */

#define SSCM_COD (*(volatile uint32_t *) 0xC3FD801CU)
#define SSCM_CANFD (*(volatile uint32_t *) 0xC3FD8068U)

static inline void Canfd_LLD_Switch_In(void) /* PRQA S 3007 # specified address is reserved in SSCM struct */
{
    /* enter privilege mode */
    SSCM_COD = 0xA5A56666U;
    SSCM_COD = 0xB6B67777U;

    /* Enter CANFD mode */
    SSCM_CANFD = 0x7fffffffU;

    /* exit privilege mode */
    SSCM_COD = 0xC7C78888U;
}

static inline void Canfd_LLD_Switch_Out(void) /* PRQA S 3007 # specified address is reserved in SSCM struct */
{
    /* enter privilege mode */
    SSCM_COD = 0xA5A56666U;
    SSCM_COD = 0xB6B67777U;

    /* Exit CANFD mode */
    SSCM_CANFD = 0U;

    /* exit privilege mode */
    SSCM_COD = 0xC7C78888U;
}

CANFDDriver* Canfd_LLD_Get_Driver(CANFDModId canfd_id);
uint32_t Canfd_LLD_Init(CANFDDriver **canfd, const CANFDConfig *config);
uint32_t Canfd_LLD_DeInit(CANFDDriver *canfd);
uint32_t Canfd_LLD_Send_Msg(const CANFDDriver *canfd, const CANFDTxMsg *tx_msg, uint32_t *msg_id);
uint8_t Canfd_LLD_Is_Msg_Transferred(const CANFDDriver *canfd, uint32_t msg_id);
uint8_t Canfd_LLD_Abort_Msg_Transfer(const CANFDDriver *canfd, uint32_t msg_id);
uint32_t Canfd_LLD_Recv_Msg(const CANFDDriver *canfd, CANFDRxMsg *rx_msg);
void Canfd_LLD_Sleep(CANFDDriver * canfd);
void Canfd_LLD_Wakeup(CANFDDriver * canfd);
void Canfd_LLD_Update_Error_Counter(CANFDDriver *canfd);

#endif
